package demo10;


import lombok.Data;

import java.io.BufferedWriter;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.concurrent.atomic.AtomicInteger;

public class BigFileSearch {
    public Search createSearch() {
        return new Search();
    }
    public BitFieldSearch createBitFieldSearch() {
        return new BitFieldSearch();
    }
    public BitFieldSearchForLowMemory createBitFieldSearchForLowMemory(int offset,int max) {
        return new BitFieldSearchForLowMemory(offset,max);
    }

    public static void main(String[] args) throws IOException, URISyntaxException {
        BigFileSearch bigFileSearch = new BigFileSearch();
        int offset = 1 * 1000 * 1000;
        int max = 10 * 1000 * 1000;
//        int offset = 16 ;
//        int max = 32;

        BigFileSearch.BitFieldSearchForLowMemory bitFieldSearchForLowMemory = bigFileSearch.
                createBitFieldSearchForLowMemory(offset,max );
        int length = (max/offset);
        int[] maxList =new int[length];
        for (int i=0;i<length;i++){
            maxList[i]=offset * i;
        }

        bitFieldSearchForLowMemory.initAndSearchForLowMemeory(maxList);

    }
    @Data
    public class BitFieldSearchForLowMemory{
        int offset = 8  ;
        int max = 32 ;
        byte[] bitfield = null;
        public BitFieldSearchForLowMemory(){
        }
        public BitFieldSearchForLowMemory(int offset,int max){
            this.offset=offset;
            this.max=max;
            this.bitfield=new byte[max / 8];
        }
        /**
         * step1:  foreach all data , get the range ,   get the range for
         * divide range for ensure the quantity of that have not missing
         *  100 * 1000 * 1000
         *
         *          int offset = 1 * 1000 * 1000;
         *         int max = 10 * 1000 * 1000;
         *  total : 10 * 1000 * 1000
         *  only 10 * 1000 * 1000  :10MB
         *  have room for 1MB  total: 10 MB
         *
         *  [0 ~ 1 * 1000 * 1000)
         *  [1 * 1000 * 1000 ~ 2 * 1000 * 1000)
         *  ...
         *
         */
        public void initAndSearchForLowMemeory(int[] max) throws URISyntaxException, IOException {
            // foreach to read
            Path sourcePath = Paths.get(
                    "F:/integration/basic/SpringWithGradle-gitee/Algorithm/simple-demo/src/test/resources/input.txt"
            );
            for (int j : max) { // [0,16), [16,32)
                int start = j ; // 0,.1
                int end = j + offset   ; // offset / 8
                Files.lines(sourcePath).forEach(line -> {
                    int i = Integer.valueOf(line);
                    searchLoop(i,start,end);
                });
                searchForLowMemeory(j/8, offset / 8 );
            }

        }
// only get the range  is  [0 -7]
        /**
         *  and [8-15] ,[16-23]
         *  // 0 8 16 24 find the 0~7
         */
        public void searchLoop(int i, int start,int end){
            if (start <= i && i <end){
                bitfield[i/8] |= 1 << (i % 8);
            }

        }
    // using the bit vector , the   bitfield  need to foreach
        public void searchForLowMemeory(int start , int offsetForBitField) {
            // start and end  16 /8 =2 , [0,2) [2,4)
            // [0,1) [1,2)
            for (int j = start; j < start + offsetForBitField; j++) {
                if(bitfield[j]!=~0){
                    for (int i = 0; i < 8; i++) {
                        if ((bitfield[j] & (1 << i)) == 0) {
                            System.out.println("missing int is : " + ( j * 8  + i));
                        }
                    }
                }
            }


        }
    }
    public class BitFieldSearch {


        public void writeFileDemo() throws IOException {
            Path sourcePath = Paths.get( // 2147483648
                    "F:/integration/basic/SpringWithGradle-gitee/Algorithm/simple-demo/src/test/resources/input.txt"
            );
            // 75MB ?
            // only need to write data whose length is  9 999 999
            int j=0;
            int[] ints = new int[10 * 1000 * 1000  ];
            //0 ~  9 999 999
            for (int i = 0; i < 10 * 1000 * 1000; i++) {
                ints[j++]=i;
            }

            BufferedWriter bufferedWriter = Files.newBufferedWriter(sourcePath, StandardOpenOption.CREATE,StandardOpenOption.WRITE);
            for (int anInt : ints) {
                bufferedWriter.write(anInt+"");
                bufferedWriter.newLine();
            }
            bufferedWriter.flush();;
            bufferedWriter.close();
        }

        public void writeFile() throws IOException {
            Path sourcePath = Paths.get(
                    "F:/integration/basic/SpringWithGradle-gitee/Algorithm/simple-demo/src/test/resources/input.txt"
            );
            // only write  40billion data , the order could be  descend     include the 0
            // using the 4g memory , i have 8g memory, should can compute completely,
            //  Integer.MAX_VALUE => 2^31 -1  1 ~ 2^31 -1, length = 2^31 -1  not contain 0
    //            when acquire Integer.MAX_VALUE-1 or Integer.MAX_VALUE ,then throws Requested array size exceeds VM limit
            // otherwise is memoryOverflowException
            // need to add memory -Xmx to 9G
            int[] ints = new int[Integer.MAX_VALUE-2];

            boolean flagMB=false,flagGB=false;
            // 1~Integer.MAX_VALUE-2
            // 0~Integer.MAX_VALUE-3  length = Integer.MAX_VALUE -2 
            for (int i = 1; i < Integer.MAX_VALUE-2; i++) {

                if(!flagMB && (i/(1024*1024)>0)){
                    flagMB=true;
                    System.out.println("1MB");
                }
                if(!flagGB&&i/(1024*1024*1024)>0){
                    flagGB=true;
                    System.out.println("1GB");
                }
                ints[i-1]=i;// 
            }
            System.out.println(String.format("%s,end the compute ,be  ready to write file ", ints.length));
            // assert  ints.length==Integer.MAX_VALUE;
            // assert ints[Integer.MAX_VALUE-1]==Integer.MAX_VALUE;
            // batch  to write
            BufferedWriter bufferedWriter = Files.newBufferedWriter(sourcePath, StandardOpenOption.CREATE,StandardOpenOption.WRITE);
            for (int anInt : ints) {
                bufferedWriter.write(anInt+"");
                bufferedWriter.newLine();
            }
            bufferedWriter.flush();;
            bufferedWriter.close();

        }
        public void divide() {
//            Path sourcePath =  Paths.get(new URI("file://F:/integration/basic/SpringWithGradle-gitee/Algorithm/simple-demo/src/test/resources/input.txt"));
//            Files.lines(sourcePath);
            // get the mark and offset ,
            // read the next
        }
        public void isExist() throws URISyntaxException {
                        Path sourcePath = Paths.get(
                                "F:/integration/basic/SpringWithGradle-gitee/Algorithm/simple-demo/src/test/resources/input.txt"
                        );
            System.out.println(String.format("%s,%s",sourcePath.toAbsolutePath(),sourcePath.toFile().exists()));

        }

        public void initAndSearch(int max) throws URISyntaxException, IOException {
            // foreach to read
            Path sourcePath = Paths.get(
                    "F:/integration/basic/SpringWithGradle-gitee/Algorithm/simple-demo/src/test/resources/input.txt"
            );
            Long maxBitNumber = Long.valueOf(max) + 1;
            int l = (int) (maxBitNumber / 8);
            System.out.println("the length of max byte array  is " + l);
            byte[] bitfield = new byte[l];
            Files.lines(sourcePath).forEach(line -> {
                int i = Integer.valueOf(line);
                bitfield[i / 8] |= 1 << (i % 8);
            });
            search(bitfield);
        }

        public void search(byte[] bitfield) {

            for (int j = 0; j < bitfield.length; j++) {
                for (int i = 0; i < 8; i++) {
                    if ((bitfield[j] & (1 << i)) == 0) {
                        System.out.println("missing int is : " + (j * 8 + i));
                    }
                }

            }
        }

    }

    public class Search {
        /**
         * question2: if the arr have duplicate integer ,
         */
        public void search(int[] arr, int j) {
            /** arr like  {1,3,5,5,10,11,17};
             binarysearch range from 0 to 20
             */
            int lastInteger = 0;
            int lasOne = arr[arr.length - 1];
            for (int i = 0, z = 0; i <= j; i++, z++) {
                if (z == arr.length) {
                    while (i <= j) {
                        System.out.println(i);
                        i++;
                    }
                    break;
                }
                if (arr[z] == i) {
                } else {
                    //  the j catch up the arr[i]
                    // not  i++ , until arr[z]==i
                    while (arr[z] != i) {
                        // 5 !=4 5==5 {1,3,5,5,5,10,11,17}
                        // z=5 i = 5 , z=5,i=6 z=5,i=7
                        System.out.println(i);
                        i++;
                        if (j < i) {
                            break;
                        }
                    }
                    int temp = 0;
                    temp = z;
                    if (++temp != arr.length) {
                        // skip duplicate ele , update z ,
                        while (arr[temp] == i) {
                            // update z
                            z = temp;
                            ++temp;
                        }
                    }

                }
            }
        }
    }

    /**
     * vector
     * 40billion need the 4g memory
     *
     * 4 * 1000 * 1000 * 1000
     * 1,2,3,4...
     * 1GB RAM
     * nlogn +   =>
     * 1. sort using the external sort , yes !
     * 2. binarySearch
     */
    public void search() {


    }

}
